﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Drawing;
using System.IO;
using System.Xml.Serialization;
using System.Windows.Media.Imaging;
using LevelEditor.Components;
using LevelEditor.Components.Layers;
using System.Windows.Forms;
using System.ComponentModel;
using LevelEditor.Dao;
using LevelEditor.Objects.Collisions;

namespace LevelEditor.Objects
{
    
    public class Tile : PictureBox
    {
        public enum TileType
        {
            CommonTile, Character, Item, Door,  
        }
        public static string[] types =
        {
            "CommonTile", "Character", "Item", "Door"
        };

        public static Dictionary<string, TileType> typeAbbreviation;

        private static Tile selectedTile;
        public static Tile CurrentSelectedTile
        {
            get { return selectedTile; }
            
        }

        private TileType type;
        public TileType myType
        {
            get { return type; }
            set { type = value; }
        }

        private string imageFormat;
        public string ImageFormat
        {
            get { return imageFormat; }
            set { imageFormat = value; }
        }

        private LayerItem layer;
        public LayerItem MyLayer
        {
            get { return layer; }
            set { layer = value; }
        }

        private bool dragging;
        public bool IsDragging
        {
            get { return dragging; }
            
        }

        private PictureBox selectedImage;

        private LibraryItem father;
        public virtual LibraryItem Father
        {
            get { return father; }
            set { father = value; }
        }

        private bool hasMoved;
        public bool HasMoved
        {
            get { return hasMoved; }
        }

        public List<Rectangle> ListRectCollisions { get; set; }

        protected List<Trigger> myTrigger = new List<Trigger>();
        public List<Trigger> MyTrigger
        {
            get { return myTrigger; }
            set { myTrigger = value; }
        }

        private int id = -1;
        public int ID
        {
            get { return id; }
            set {
                if (id < 0)
                    id = value;
            }
        }

        public new Image Image
        {
            get { return base.Image; }
            set
            {
                base.Image = value;

                this.selectedImage = new PictureBox();
                this.selectedImage.Image = new Bitmap(@"Images\selectedTile.png");
                
                this.selectedImage.Width = this.Image.Width;
                this.selectedImage.Height = this.Image.Height;
                this.selectedImage.Enabled = false;
                this.selectedImage.BackColor = Color.Transparent;
                this.selectedImage.SizeMode = PictureBoxSizeMode.StretchImage;
                this.selectedImage.Dock = DockStyle.Fill;

                this.Width = Image.Width;
                this.Height = Image.Height;
            }
        }

        public int PositionX
        {
            get { return Location.X; }
            set { Location = new Point(value, this.Location.Y); }
        }


        public int PositionY
        {
            get { return Location.Y; }
            set { Location = new Point(this.Location.X, value); }
        }

        private byte[] imageBuffer;
        public byte[] ImageBuffer
        {
            get
            {
                if (imageBuffer != null) return imageBuffer;

                MemoryStream mStream = new MemoryStream();
                Image.Save(mStream, System.Drawing.Imaging.ImageFormat.Png);
                BitmapDecoder decoder = BitmapDecoder.Create(mStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);

                BitmapSource bitmapSourcce = decoder.Frames[0];

                imageBuffer = null;
                
                if (Image != null)
                {
                    using (var stream = new MemoryStream())
                    {
                        var encoder = new PngBitmapEncoder();
                        encoder.Frames.Add(BitmapFrame.Create(bitmapSourcce));
                        encoder.Save(stream);
                        imageBuffer = stream.ToArray();

                    }
                    
                }

                return imageBuffer;
            }
        }

        private bool displayingProperties;
        public bool DisplayingProperties
        {
            get { return displayingProperties; }
        }

        protected LevelEditor editor;

        private Point lastMousePosition;

        private Point dropPosition;

        public List<Behavior> standAloneBehaviors = new List<Behavior>();
        
        public Tile(LevelEditor editor) : base()
        {
            this.editor = editor;
            Initialize();
            
        }

        public Tile()
        {
            Initialize();
        }

        private void Initialize()
        {
            dragging = false;
            MouseDown += Tile_MouseDown;
            MouseUp += Tile_MouseUp;
            MouseMove += Tile_MouseMove;

            this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.standAloneBehaviors = new List<Behavior>();

            this.displayingProperties = false;
            this.SizeMode = PictureBoxSizeMode.StretchImage;
            this.Anchor = AnchorStyles.Left | AnchorStyles.Top;
            this.dropPosition = new Point();
            this.LostFocus += Tile_LostFocus;

        }

        void Tile_LostFocus(object sender, EventArgs e)
        {
            this.editor.stage1.StopShowingWaypoints();
        }


        protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                this.Parent.Controls.Remove(selectedTile);
                this.MyLayer.myLayer.Remove(selectedTile);
                selectedTile = null;
            }
 	        base.OnPreviewKeyDown(e);
        }

        protected virtual void Tile_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right) return;

            if (!dragging) return;

            dragging = false;

            if (dropPosition.X < 0) dropPosition.X = 0;
            if (dropPosition.Y < 0) dropPosition.Y = 0;
            if (dropPosition.X > MyLayer.TileWidth * MyLayer.Cols) dropPosition.X = (MyLayer.TileWidth * MyLayer.Cols) - this.Width;
            if (dropPosition.Y > MyLayer.TileHeight * MyLayer.Rows) dropPosition.Y = (MyLayer.TileHeight * MyLayer.Rows) - this.Height;

            this.Location = this.dropPosition;

            this.editor.stage1.ClearGraphics();
        }

        void Tile_MouseDown(object sender, MouseEventArgs e)
        {

			if (LevelEditor.IsCreatingConnectors && Tile.CurrentSelectedTile != null && Tile.CurrentSelectedTile != this)
            {
                Tile tile = editor.stage1.GetTileInControls(this);
                if (tile != null)
                {
                    NewTrigger newTriggerForm = new NewTrigger(Tile.CurrentSelectedTile, tile);
                    newTriggerForm.Show();
                    newTriggerForm.BringToFront();

                    Tile.CurrentSelectedTile.Deselect();
                }
                // o trigger cadastrado eh enviado para os dois tiles

                return;
            }

			if (e.Button == System.Windows.Forms.MouseButtons.Right) return;

            if (LayerPanel.CurrentLayer == null) return;

            if (!this.layer.LayerName.Text.Equals(LayerPanel.CurrentLayer.LayerName.Text)) return;

            if (e.Button != System.Windows.Forms.MouseButtons.Left) return;

            Select();

            if (LevelEditor.IsCreatingConnectors) return;

            dragging = true;

            this.lastMousePosition = e.Location;

            //Select();
        }

        protected virtual void Tile_MouseMove(object sender, MouseEventArgs e)
        {
            
            if (dragging)
            {
                Point p = new Point();
                p.X = e.X + this.Left;
                p.Y = e.Y + this.Top;
                this.Left = p.X - lastMousePosition.X;
                this.Top = p.Y - lastMousePosition.Y;

                hasMoved = true;

                TileMove();
            }
        }

        private void TileMove()
        {
            if (Tile.CurrentSelectedTile == null) return;

            if (!Tile.CurrentSelectedTile.IsDragging) return;

            int hScrollValue = 0;
            int vScrollValue = 0;

            Point mousePosition = this.editor.stage1.PointToClient(Cursor.Position);

            int tileWidth = (int)(Tile.CurrentSelectedTile.MyLayer.TileWidth * this.editor.stage1.CurrentZoom);
            int tileHeight = (int)(Tile.CurrentSelectedTile.MyLayer.TileHeight * this.editor.stage1.CurrentZoom);

            int col = (int)(mousePosition.X / tileWidth);
            int row = (int)(mousePosition.Y / tileHeight);

            if (this.editor.stage1.AutoScrollPosition.Y % tileHeight != 0)
            {
                int legalValue = (int)Math.Abs(Math.Ceiling(this.editor.stage1.AutoScrollPosition.Y / (float)tileHeight) * tileHeight);
                vScrollValue = (legalValue + this.editor.stage1.AutoScrollPosition.Y) * -1; // autoscrollposition is < 0
            }

            if (this.editor.stage1.AutoScrollPosition.X % tileWidth != 0)
            {
                int legalValue = (int)Math.Abs(Math.Ceiling(this.editor.stage1.AutoScrollPosition.X / (float)tileWidth) * tileWidth);
                hScrollValue = (legalValue + this.editor.stage1.AutoScrollPosition.X) * -1;
            }

            this.dropPosition.X = (col * tileWidth) - hScrollValue;
            this.dropPosition.Y = (row * tileHeight) - vScrollValue;

        }

        public new void Select()
        {
            if (selectedTile == this) return;

            if (selectedTile != null)
                selectedTile.Deselect();

            selectedTile = this;

            this.selectedImage.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.Controls.Add(selectedImage);
            this.Controls.SetChildIndex(selectedImage, this.Controls.Count - 1);
            
            this.Focus();

            hasMoved = false;

            if (!DisplayingProperties)
            {
                this.displayingProperties = true;
            }

            this.editor.propertiesPanel1.ShowProperties();

            if (this.myType == TileType.Character) this.editor.EnableWaypointsEditor();
        }

        public virtual void Deselect()
        {
            this.Controls.Remove(selectedImage);
            this.BorderStyle = System.Windows.Forms.BorderStyle.None;

            hasMoved = false;

            this.displayingProperties = false;
            selectedTile = null;

            this.editor.stage1.StopShowingWaypoints();
        }

        public static TileType ParseType(string strType)
        {
            return typeAbbreviation[strType];
        }

        public static void InitializeTiletypes()
        {
            typeAbbreviation = new Dictionary<string, TileType>();
            TileType[] values = (TileType[])Enum.GetValues(typeof(TileType));

            for (int k = 0; k < Enum.GetValues(typeof(TileType)).Length; k++)
            {
                typeAbbreviation.Add(types[k], values[k]);
            }
        }

        public void MyTriggerClicked(object sender, MouseEventArgs args)
        {
            if (args.Button == System.Windows.Forms.MouseButtons.Right) return;
            if ((sender as Label) == null) return;
            if ((((sender as Label).Parent as TableLayoutPanel)) == null) return;

            Trigger trigger = MyTrigger.Find(
                delegate(Trigger t)
                {
                    return t.Name == (sender as Label).Text;
                });
            
            

            NewTrigger newTriggerForm = new NewTrigger(trigger);
            newTriggerForm.Show();
            newTriggerForm.BringToFront();

            //TableLayoutPanel tlp = ((sender as ComboBox).Parent as TableLayoutPanel);
            //ComboBox option = (sender as ComboBox);

            //if (!MyTrigger.ContainsKey(tlp.GetControlFromPosition(0, tlp.GetRow(option)).Text))
            //    MyTrigger.Add(tlp.GetControlFromPosition(0, tlp.GetRow(option)).Text, option.Text);
            //else
            //    MyTrigger[tlp.GetControlFromPosition(0, tlp.GetRow(option)).Text] = option.Text;

            //this.Father.Tile.Location = p;
        }


        public Tile Clone()
        {
            Tile tile = new Tile(this.editor);
            tile.imageFormat = this.imageFormat;
            tile.Name = this.Name;
            tile.myType = this.myType;
            tile.Image = this.Image;
            
            Point p = new Point(this.Location.X, this.Location.Y);
            
            tile.Location = p;
            tile.Width = this.Width;
            tile.Height = this.Height;
            
            
            return tile;
        }
    }
}
